{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-04-04T12:12:44.852621Z",
     "start_time": "2025-04-04T12:12:41.463573Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "import talib\n",
    "import yfinance as yf\n",
    "import matplotlib.pyplot as plt\n",
    "import pytz\n",
    "from binance.spot import Spot\n",
    "from datetime import datetime\n",
    "\n",
    "# 3. 时间戳转换（含时区处理）\n",
    "def convert_to_beijing_time(ts):\n",
    "    tz = pytz.timezone(\"Asia/Shanghai\")\n",
    "    return datetime.fromtimestamp(ts // 1e3, tz)\n",
    "\n",
    "\n",
    "def get_data(interval, limit):\n",
    "    # 1. 获取K线原始数据\n",
    "    client = Spot(base_url=\"https://data-api.binance.vision\")\n",
    "    # interval 1s, 1m, 5m, 1h, 1d,\n",
    "    # 1125-1216 1732475182000-1734289582000 震荡\n",
    "    # 1106-1125 1730833582000-1732475182000 上涨\n",
    "    # 0124 1737659180000\n",
    "    klines = client.klines(\n",
    "        \"BTCUSDT\",\n",
    "        interval=interval,\n",
    "        limit=limit,\n",
    "        # startTime=\"1730833582000\",\n",
    "        # startTime=\"1737659180000\",\n",
    "        # startTime=\"1730833582000\",\n",
    "        # startTime=\"1732475182000\",\n",
    "        # endTime=\"1734289582000\",\n",
    "    )  # 示例：BTC/USDT 1小时K线\n",
    "\n",
    "    # 2. 转换为结构化数据\n",
    "    df = pd.DataFrame(\n",
    "        klines,\n",
    "        columns=[\n",
    "            \"Open Time\",\n",
    "            \"Open\",\n",
    "            \"High\",\n",
    "            \"Low\",\n",
    "            \"Close\",\n",
    "            \"Volume\",\n",
    "            \"Close Time\",\n",
    "            \"Quote Asset Volume\",\n",
    "            \"Number of Trades\",\n",
    "            \"Taker Buy Base\",\n",
    "            \"Taker Buy Quote\",\n",
    "            \"Ignore\",\n",
    "        ],\n",
    "    )\n",
    "\n",
    "    df[\"Time\"] = df[\"Open Time\"].apply(convert_to_beijing_time)\n",
    "\n",
    "    # # 4. 构建OHLC数据框架\n",
    "    ohlc = df.copy()\n",
    "    ohlc = ohlc.set_index(\"Time\").astype(float)  # 确保数值类型正确\n",
    "\n",
    "    return ohlc\n",
    "\n",
    "\n",
    "# pre = get_data(interval=\"4h\", limit=500)\n",
    "# adf = get_data(interval=\"1h\", limit=500)\n",
    "# pre = get_data(interval=\"30m\", limit=500)\n",
    "adf = get_data(interval=\"3m\", limit=500)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-04-04T12:12:53.757643Z",
     "start_time": "2025-04-04T12:12:52.864111Z"
    }
   },
   "outputs": [],
   "source": [
    "\n",
    "# import pydevd_pycharm\n",
    "#\n",
    "# pydevd_pycharm.settrace('localhost', port=$SERVER_PORT, stdoutToServer=True, stderrToServer=True)\n",
    "\n",
    "pd.set_option('display.max_rows', 1000)\n",
    "pd.set_option('display.max_columns', 1000)\n",
    "\n",
    "\n",
    "# 收益\n",
    "# 做多\n",
    "def long_profit(open_at, now):\n",
    "    return now / open_at - 1\n",
    "\n",
    "\n",
    "# 做空\n",
    "def short_profit(open_at, now):\n",
    "    return 1 - now / open_at\n",
    "\n",
    "\n",
    "# MACD KDJ RSI B/S信号交易策略 15m 30m 1h 1d # FOCUS ON \"30m\" !!! 1.1%\n",
    "class MACDKDJRSI:\n",
    "\n",
    "    def __init__(\n",
    "            self,\n",
    "            model=1,\n",
    "            tend_period=\"\",\n",
    "            tend_interval=\"\",\n",
    "            period=\"1y\",\n",
    "            interval=\"1d\",\n",
    "            limit=100,\n",
    "            over_buy=80,\n",
    "            over_sell=30,\n",
    "            use_cache=False\n",
    "    ):\n",
    "        self.model = model\n",
    "        self.tend_interval = tend_interval\n",
    "        self.period = period\n",
    "        self.interval = interval\n",
    "        self.limit = limit\n",
    "        self.over_buy = over_buy\n",
    "        self.over_sell = over_sell\n",
    "        self.tend_period = \"\"\n",
    "        self.use_cache = use_cache\n",
    "\n",
    "        self.df = self.get_data()\n",
    "        self.calculate_all(self.df)\n",
    "\n",
    "        self.tend_period = tend_period\n",
    "        if self.tend_interval != \"\":\n",
    "            self.period = self.tend_period\n",
    "            self.interval = self.tend_interval\n",
    "            self.limit = self.limit\n",
    "            self.pre_cycle = self.get_data()\n",
    "            self.calculate_all(self.pre_cycle)\n",
    "\n",
    "        self.marketing()\n",
    "\n",
    "    def get_data(self):\n",
    "        # use cache data\n",
    "        if self.use_cache:\n",
    "            if self.tend_period != \"\":\n",
    "                return pre\n",
    "            else:\n",
    "                return adf\n",
    "\n",
    "        # 获取历史数据（示例用AAPL）\n",
    "        # start = \"2024-01-01\"\n",
    "        # end = \"2025-02-26\"\n",
    "        # self.df = yf.download(tickers=\"BTC-USD\", period=self.period, interval=self.interval)\n",
    "        # 1d season\n",
    "        # 1h 3day\n",
    "        # 30m day\n",
    "        # 15m day\n",
    "        # self.df.index = self.df.index.tz_localize('UTC')\n",
    "        # self.df.index = self.df.index.tz_convert(pytz.timezone('Asia/Shanghai'))\n",
    "        # 验证时区状态\n",
    "        # if self.df.index.tz is not None:\n",
    "        #     # 直接转换为上海时区\n",
    "        #     self.df.index = self.df.index.tz_convert(pytz.timezone('Asia/Shanghai'))\n",
    "        # else:\n",
    "        #     # 先本地化为 UTC 再转换\n",
    "        #     self.df.index = self.df.index.tz_localize('UTC').tz_convert('Asia/Shanghai')\n",
    "\n",
    "        # 1. 获取K线原始数据\n",
    "        client = Spot(base_url=\"https://data-api.binance.vision\")\n",
    "        # interval 1s, 1m, 5m, 1h, 1d,\n",
    "        # 1125-1216 1732475182000-1734289582000 震荡\n",
    "        # 1106-1125 1730833582000-1732475182000 上涨\n",
    "        # 0124 1737659180000\n",
    "        klines = client.klines(\n",
    "            \"BTCUSDT\",\n",
    "            interval=self.interval,\n",
    "            limit=self.limit,\n",
    "            # startTime=\"1730833582000\",\n",
    "            # startTime=\"1737659180000\",\n",
    "            # startTime=\"1730833582000\",\n",
    "            # startTime=\"1732475182000\",\n",
    "            # endTime=\"1734289582000\",\n",
    "        )  # 示例：BTC/USDT 1小时K线\n",
    "\n",
    "        # 2. 转换为结构化数据\n",
    "        df = pd.DataFrame(\n",
    "            klines,\n",
    "            columns=[\n",
    "                \"Open Time\",\n",
    "                \"Open\",\n",
    "                \"High\",\n",
    "                \"Low\",\n",
    "                \"Close\",\n",
    "                \"Volume\",\n",
    "                \"Close Time\",\n",
    "                \"Quote Asset Volume\",\n",
    "                \"Number of Trades\",\n",
    "                \"Taker Buy Base\",\n",
    "                \"Taker Buy Quote\",\n",
    "                \"Ignore\",\n",
    "            ],\n",
    "        )\n",
    "\n",
    "        df[\"Time\"] = df[\"Open Time\"].apply(self.convert_to_beijing_time)\n",
    "\n",
    "        # # 4. 构建OHLC数据框架\n",
    "        ohlc = df.copy()\n",
    "        ohlc = ohlc.set_index(\"Time\").astype(float)  # 确保数值类型正确\n",
    "        ohlc = ohlc.astype('Open Time', float)  # 确保数值类型正确\n",
    "\n",
    "        return ohlc\n",
    "\n",
    "    # 3. 时间戳转换（含时区处理）\n",
    "    def convert_to_beijing_time(self, ts):\n",
    "        tz = pytz.timezone(\"Asia/Shanghai\")\n",
    "        return datetime.fromtimestamp(ts // 1e3, tz)\n",
    "\n",
    "    # ----------------------------\n",
    "    # 1. 计算MACD指标（参考‌:ml-citation{ref=\"4\" data=\"citationList\"}实现）\n",
    "    # ----------------------------\n",
    "    def calculate_macd(self, df):\n",
    "        # 计算MACD指标\n",
    "        # (\n",
    "        #     df[\"MACD\"],\n",
    "        #     df[\"MACD_Signal_Line\"],\n",
    "        #     df[\"Histogram\"],\n",
    "        # ) = talib.MACD(\n",
    "        #     df[\"Close\"].values.flatten(), fastperiod=12, slowperiod=26, signalperiod=9\n",
    "        # )\n",
    "\n",
    "        df[\"EMA12\"] = df[\"Close\"].ewm(span=12, adjust=False).mean()\n",
    "        df[\"EMA26\"] = df[\"Close\"].ewm(span=26, adjust=False).mean()\n",
    "        df[\"DIF\"] = df[\"EMA12\"] - df[\"EMA26\"]\n",
    "        df[\"DEA\"] = df[\"DIF\"].ewm(span=9, adjust=False).mean()\n",
    "        df[\"MACD\"] = (df[\"DIF\"] - df[\"DEA\"]) * 2\n",
    "        # return df\n",
    "\n",
    "        # 计算涨跌幅\n",
    "        df[\"Change\"] = df[\"Close\"].pct_change()\n",
    "        df[\"ChangeOfChange\"] = df[\"Change\"].pct_change()\n",
    "\n",
    "        # 将涨跌幅转换为百分比形式\n",
    "        # df[\"Change(%)\"] = df[\"Change\"].apply(\n",
    "        #     lambda x: \"{:.2f}%\".format(x * 100)\n",
    "        # )\n",
    "        return df\n",
    "\n",
    "    # ----------------------------\n",
    "    # 2. 计算KDJ指标（参考‌:ml-citation{ref=\"4,6\" data=\"citationList\"}实现）\n",
    "    # ----------------------------\n",
    "    def calculate_kdj(self, df, n=9, m1=3, m2=3):\n",
    "        low_min = df[\"Low\"].rolling(n, min_periods=1).min()\n",
    "        high_max = df[\"High\"].rolling(n, min_periods=1).max()\n",
    "        df[\"RSV\"] = (df[\"Close\"] - low_min) / (high_max - low_min) * 100\n",
    "        df[\"K\"] = df[\"RSV\"].ewm(alpha=1 / m1, adjust=False).mean()\n",
    "        df[\"D\"] = df[\"K\"].ewm(alpha=1 / m2, adjust=False).mean()\n",
    "        df[\"J\"] = 3 * df[\"K\"] - 2 * df[\"D\"]\n",
    "        return df\n",
    "\n",
    "    # 3.计算RSI\n",
    "    def calculate_rsi(self, df, window=14):\n",
    "        # 提取收盘价序列\n",
    "        close = df[\"Close\"]\n",
    "\n",
    "        # 计算价格变化差值\n",
    "        delta = close.diff(1)\n",
    "\n",
    "        # 分离涨跌幅\n",
    "        gain = delta.where(delta > 0, 0)\n",
    "        loss = -delta.where(delta < 0, 0)\n",
    "\n",
    "        # 计算平均涨跌幅（使用指数移动平均）\n",
    "        avg_gain = gain.ewm(alpha=1 / window, min_periods=window).mean()\n",
    "        avg_loss = loss.ewm(alpha=1 / window, min_periods=window).mean()\n",
    "\n",
    "        # 计算RS和RSI\n",
    "        rs = avg_gain / avg_loss\n",
    "        df[\"RSI\"] = 100 - (100 / (1 + rs))\n",
    "        return df\n",
    "\n",
    "    # 执行计算\n",
    "    def calculate_all(self, df):\n",
    "        self.calculate_macd(df)\n",
    "        self.calculate_kdj(df)\n",
    "        self.calculate_rsi(df)\n",
    "        # self.df = self.df.fillna(0)\n",
    "\n",
    "    def marketing_data(self, cnt=5):\n",
    "        return self.df[(self.df[\"Buy_Signal\"]) | (self.df[\"Sell_Signal\"])].tail(cnt)\n",
    "\n",
    "    def marketing(self):\n",
    "        # ----------------------------\n",
    "        # 3. 生成交易信号\n",
    "        # ----------------------------\n",
    "        # MACD金叉/死叉判断\n",
    "        self.df[\"MACD_Cross\"] = np.where(self.df[\"DIF\"] > self.df[\"DEA\"], 1, -1)\n",
    "        self.df[\"MACD_Signal\"] = self.df[\"MACD_Cross\"].diff()\n",
    "\n",
    "        # KDJ超买超卖判断（J>80超买，J<20超卖）\n",
    "        self.df[\"KDJ_Over\"] = np.where(self.df[\"J\"] > self.df[\"D\"], 1, -1)\n",
    "        # data[\"KDJ_Over\"] = (data[\"J\"] > data[\"D\"]) & data[\"J\"]<50\n",
    "\n",
    "        # 综合信号（MACD金叉+KDJ超卖时买入且RSI小于70时买入）\n",
    "        if self.model == 1:\n",
    "            self.df[\"Buy_Signal\"] = (\n",
    "                                            (self.df[\"MACD_Signal\"] > 0) & (self.df[\"KDJ_Over\"] == 1)\n",
    "                                    ) & (self.df[\"RSI\"] < 80)\n",
    "            self.df[\"Sell_Signal\"] = (\n",
    "                                             (self.df[\"MACD_Signal\"] < 0) & (self.df[\"KDJ_Over\"] == -1)\n",
    "                                     ) & (self.df[\"RSI\"] > 30)\n",
    "\n",
    "        # 日K方向\n",
    "        # \tB\tS\n",
    "        # KDJ_OVER\tJ>D\tJ<D\n",
    "        # 入场时机\tJ线上穿50\tJ线下穿50\n",
    "        if self.model == 2:\n",
    "            self.df[\"Buy_Signal\"] = (\n",
    "                    (self.df[\"KDJ_Over\"] == 1)\n",
    "                    & (self.df[\"MACD_Signal\"] > 0)\n",
    "                    & (self.df[\"J\"] > 50)\n",
    "            )\n",
    "            self.df[\"Sell_Signal\"] = (\n",
    "                    (self.df[\"KDJ_Over\"] == -1)\n",
    "                    & (self.df[\"MACD_Signal\"] < 0)\n",
    "                    & (self.df[\"J\"] < 50)\n",
    "            )\n",
    "\n",
    "        # rsi high\n",
    "        if self.model == 3:\n",
    "            # macd <0  dif<dea j<50 rsi<30\n",
    "            self.df[\"Buy_Signal\"] = (\n",
    "                    (self.df[\"MACD\"] < 0)\n",
    "                    & (self.df[\"DIF\"] < self.df[\"DEA\"])\n",
    "                    & (self.df[\"J\"] < 50)\n",
    "                    & (self.df[\"RSI\"] < self.over_sell)\n",
    "            )\n",
    "            # macd >0 dif>dea j>50 rsi>80\n",
    "            self.df[\"Sell_Signal\"] = (\n",
    "                    (self.df[\"MACD\"] > 0)\n",
    "                    & (self.df[\"DIF\"] > self.df[\"DEA\"])\n",
    "                    & (self.df[\"J\"] > 50)\n",
    "                    & (self.df[\"RSI\"] > self.over_buy)\n",
    "            )\n",
    "            \n",
    "            self.df[\"Status\"] = self.df[\"Open\"] > self.df[\"Close\"]\n",
    "\n",
    "            if self.tend_interval != \"\":\n",
    "                self.df[\"RSI_Over_Buy\"] = np.where(self.df[\"RSI\"] > self.over_buy, 1, 0)\n",
    "                self.df[\"RSI_Over_Buy_Signal\"] = self.df[\"RSI_Over_Buy\"].diff()\n",
    "\n",
    "                self.df[\"RSI_Over_Sell\"] = np.where(self.df[\"RSI\"] < self.over_sell, 1, 0)\n",
    "                self.df[\"RSI_Over_Sell_Signal\"] = self.df[\"RSI_Over_Sell\"].diff()\n",
    "\n",
    "                #\n",
    "                pre_cycle_cnt1 = -1\n",
    "\n",
    "                def tend(row):\n",
    "                    found = self.pre_cycle[(self.pre_cycle[\"Open Time\"] <= row[\"Open Time\"])].iloc[pre_cycle_cnt1]\n",
    "                    return found[\"MACD\"] > 0\n",
    "\n",
    "                def tend_time(row):\n",
    "                    found = self.pre_cycle[(self.pre_cycle[\"Open Time\"] <= row[\"Open Time\"])]\n",
    "                    return found[\"Open Time\"].iloc[pre_cycle_cnt1].apply(self.convert_to_beijing_time)\n",
    "\n",
    "                # self.df[\"Tend\"] = self.df.apply(tend)\n",
    "                # self.df[\"TendTime\"] = self.df.apply(tend_time)\n",
    "                # try:\n",
    "                # except Exception as e:\n",
    "                #     print(e)\n",
    "                #     pass\n",
    "\n",
    "                self.df[\"Sell_Signal\"] = (\n",
    "                    self.df[\"Sell_Signal\"])  # & (self.df[\"Tend\"] == False) # &(self.df[\"RSI_Over_Buy_Signal\"]<0) # \n",
    "                # Over_Sell穿出超买线 REAL BUY?\n",
    "                # self.df[\"Buy_Signal\"] = (self.df[\"RSI_Over_Sell_Signal\"] < 0)  #& (self.df[\"Tend\"] == True)\n",
    "                self.df[\"Buy_Signal\"] = (\n",
    "                    self.df[\"Buy_Signal\"])  # &(self.df[\"RSI_Over_Sell_Signal\"]<0) & (self.df[\"Tend\"] == True)\n",
    "\n",
    "        # print(data.head(10))\n",
    "\n",
    "        # filter_data = self.df[(self.df[\"Buy_Signal\"]) | (self.df[\"Sell_Signal\"])]\n",
    "        #\n",
    "        # print(filter_data.head(100))\n",
    "\n",
    "        # data.head(500)\n",
    "\n",
    "    # ----------------------------\n",
    "    # 4. 回测展示（简化版）\n",
    "    # ----------------------------\n",
    "\n",
    "    # 数据可视化\n",
    "    def backtest(self):\n",
    "        plt.figure(figsize=(16, 12))\n",
    "        # 价格与MACD\n",
    "        plt.subplot(4, 1, 1)\n",
    "        plt.plot(self.df[\"Close\"], label=\"Price\")\n",
    "        plt.plot(\n",
    "            self.df[self.df[\"Buy_Signal\"]].index,\n",
    "            self.df[\"Close\"][self.df[\"Buy_Signal\"]],\n",
    "            \"^\",\n",
    "            markersize=10,\n",
    "            color=\"r\",\n",
    "        )\n",
    "        plt.plot(\n",
    "            self.df[self.df[\"Sell_Signal\"]].index,\n",
    "            self.df[\"Close\"][self.df[\"Sell_Signal\"]],\n",
    "            \"v\",\n",
    "            markersize=10,\n",
    "            color=\"g\",\n",
    "        )\n",
    "\n",
    "        # MACD指标\n",
    "        plt.subplot(4, 1, 2)\n",
    "        plt.plot(self.df[\"DEA\"], label=\"DEA\")\n",
    "        plt.plot(self.df[\"DIF\"], label=\"DIF\")\n",
    "\n",
    "        plt.bar(\n",
    "            self.df.index,\n",
    "            self.df[\"MACD\"],\n",
    "            label=\"MACD\",\n",
    "            color=[(\"red\" if x > 0 else \"green\") for x in self.df[\"MACD\"]],\n",
    "            alpha=0.5,\n",
    "        )\n",
    "        plt.tight_layout()\n",
    "        plt.legend(loc=\"lower left\", frameon=False)\n",
    "\n",
    "        # plt.bar(\n",
    "        #     data.index,\n",
    "        #     data[\"Histogram\"],\n",
    "        #     color=[(\"red\" if x > 0 else \"green\") for x in data[\"Histogram\"]],\n",
    "        #     alpha=0.5,\n",
    "        # )\n",
    "\n",
    "        # KDJ指标\n",
    "        plt.subplot(4, 1, 3)\n",
    "        plt.plot(self.df[\"K\"], label=\"K\")\n",
    "        plt.plot(self.df[\"J\"], label=\"J\")\n",
    "        plt.plot(self.df[\"D\"], label=\"D\")\n",
    "        plt.axhline(80, linestyle=\"--\", color=\"gray\")\n",
    "        plt.axhline(50, linestyle=\"--\", color=\"gray\")\n",
    "        plt.axhline(20, linestyle=\"--\", color=\"gray\")\n",
    "        plt.legend(loc=\"lower left\", frameon=False)\n",
    "\n",
    "        # RSI绘制\n",
    "        plt.subplot(4, 1, 4)\n",
    "        plt.plot(self.df[\"RSI\"], color=\"navy\")\n",
    "        plt.fill_between(self.df.index, 30, 70, color=\"lightgrey\", alpha=0.3)\n",
    "        plt.axhline(70, color=\"red\", linewidth=0.5)\n",
    "        plt.axhline(30, color=\"green\", linewidth=0.5)\n",
    "\n",
    "        plt.show()\n",
    "\n",
    "\n",
    "# fix err mark:\n",
    "\n",
    "# Valid periods: 1d,5d,1mo,3mo,6mo,1y,2y,5y,10y,ytd,max\n",
    "# Valid intervals: 1m,2m,5m,15m,30m,60m,90m,1h,1d,5d,1wk,1mo,3mo\n",
    "# dd = MACDKDJRSI(interval=\"4h\", limit=1000)\n",
    "# dd = MACDKDJRSI(interval=\"15m\", limit=500)\n",
    "# dd = MACDKDJRSI(model=3, interval=\"30m\", limit=200)\n",
    "# dd = MACDKDJRSI(model=3, tend_interval=\"4h\", interval=\"1h\", limit=500, over_buy=70,over_sell=30,use_cache=False)\n",
    "# dd = MACDKDJRSI(model=3, tend_interval=\"1h\", interval=\"30m\", limit=500, over_buy=70, over_sell=30, use_cache=True)\n",
    "dd = MACDKDJRSI(model=3, tend_interval=\"30m\", interval=\"15m\", limit=500, over_buy=70, over_sell=30, use_cache=True)\n",
    "# dd = MACDKDJRSI(model=3, tend_interval=\"4h\", interval=\"30m\", limit=500, over_buy=70,over_sell=30,use_cache=True)\n",
    "df = dd.df\n",
    "dd.backtest()\n",
    "dd.marketing_data(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-04-04T12:13:19.963586Z",
     "start_time": "2025-04-04T12:13:19.591753Z"
    }
   },
   "outputs": [],
   "source": [
    "# 创建辅助列标记下一行是否符合条件 \n",
    "df[\"下一行符合条件\"] = df[\"成绩提升\"].shift(-1) != 0 \n",
    " \n",
    "# 筛选当前行或下一行符合条件的行 \n",
    "result_df = df[(df[\"成绩提升\"] != 0) | (df[\"下一行符合条件\"])]\n",
    "result_df = result_df.drop(columns=[\" 下一行符合条件\"])\n",
    " \n",
    "print(result_df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = dd.df\n",
    "pre_cycle = dd.pre_cycle\n",
    "pre_cycle_cnt1 = -1\n",
    "\n",
    "# df3 = df.join(pre_cycle.set_index('Open Time'),on='Open Time',how='left')\n",
    "# df\n",
    "# def tend(row):\n",
    "#     found = pre_cycle[(pre_cycle['Open Time'] <= row['Open Time'])]\n",
    "#     # [pre_cycle_cnt1]\n",
    "#     print(found)\n",
    "#     return 0, found[\"MACD\"] > 0\n",
    "# \n",
    "# # def tend_time(row):\n",
    "# #     found = pre_cycle[(pre_cycle[\"Open Time\"] <= row[\"Open Time\"])]\n",
    "# #     return found[\"Open Time\"].iloc[pre_cycle_cnt1].apply(self.convert_to_beijing_time)\n",
    "# \n",
    "# df[\"Tend\"] = df.apply(tend)\n",
    "# # dd.pre_cycle.index[-1] "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "pre_cycle['Tend'] = pre_cycle['MACD']>0\n",
    "# pre_cycle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 单向做空 buy_signal\n",
    "# 周期达到2.5%幅或信号离场\n",
    "# 买入一个周期Close不足0.35%幅度撤退\n",
    "# 大方向不设置止盈 否则 1.1\n",
    "# 前提日K线趋势下跌 1.24开始\n",
    "\n",
    "# run on 20-02\n",
    "# backtest\n",
    "# TODO:监听\n",
    "# 30m SellSignal 检查\n",
    "# 周期Close不足0.35%幅度 撤退通知\n",
    "# 复利止盈\n",
    "# 手续费计算\n",
    "# 趋势检查 pine script done\n",
    "\n",
    "\n",
    "class BackTester:\n",
    "    def __init__(\n",
    "            self,\n",
    "            df=None,\n",
    "            capital=1000,\n",
    "            # position = 0 , # -1空 1多,\n",
    "            leverage=10,  # 10倍杠杆\n",
    "            # overp = 100 / leverage / 100,  # 爆仓涨跌幅,\n",
    "            profit=0,\n",
    "            stop=0.35,  # 势力不足撤退 买入下一个周期Close不足0.35%幅度撤退,\n",
    "            take=3.5,  # 涨跌幅度%\n",
    "            # close=1.25,  # 涨跌幅度%\n",
    "            auto_stop=False,\n",
    "            loss=90,  # 10%止损,\n",
    "            # operate = 0,\n",
    "            # khigh = 0,\n",
    "            strong_will=-1.5,\n",
    "            # fee_profit = 0.1 / 1e2 * leverage,\n",
    "    ):\n",
    "        self.df = df\n",
    "        self.capital = capital\n",
    "        self.open_at = 0\n",
    "        self.position = 0\n",
    "        self.leverage = leverage\n",
    "        self.overp = 100 / leverage\n",
    "        self.profit = profit\n",
    "        self.take = take\n",
    "        self.stop = stop\n",
    "        self.auto_stop = auto_stop\n",
    "        self.loss = 1 - loss / 1e2\n",
    "        self.operate = 0\n",
    "        # self.khigh=khigh\n",
    "        self.strong_will = strong_will\n",
    "        self.fee_profit = 0.1 / 1e2 * leverage\n",
    "        self.log = pd.DataFrame(\n",
    "            {\n",
    "                \"Time\": [],\n",
    "                \"Open\": [],\n",
    "                \"Close\": [],\n",
    "                \"Profit\": [],\n",
    "                \"Capital\": [],\n",
    "                \"Buy_Signal\": [],\n",
    "                \"Sell_Signal\": [],\n",
    "                \"Operate\": [],\n",
    "                \"Symbol\": [],\n",
    "            }\n",
    "        )\n",
    "\n",
    "    # 收益\n",
    "    # 做多\n",
    "    def long_profit(a, now):\n",
    "        return now / a - 1\n",
    "\n",
    "    # 做空\n",
    "    def short_profit(a, now):\n",
    "        return 1 - now / a\n",
    "\n",
    "    def close_cage(self, time, row, symbol):\n",
    "        self.capital = self.capital * self.profit\n",
    "        # close = row[\"Close\"]\n",
    "        # self.position = self.position\n",
    "        self.operate += 1\n",
    "        # self.out_put.add\n",
    "        # self.log.append()\n",
    "        # {\"Site\": [\"Google\", \"Runoob\", \"Wiki\"], \"Age\": [10, 12, 13]}\n",
    "        new_row = pd.DataFrame(\n",
    "            [\n",
    "                [\n",
    "                    time,\n",
    "                    self.open_at,\n",
    "                    row[\"Close\"],\n",
    "                    self.profit,\n",
    "                    self.capital,\n",
    "                    row[\"Buy_Signal\"],\n",
    "                    row[\"Sell_Signal\"],\n",
    "                    self.operate,\n",
    "                    symbol,\n",
    "                ]\n",
    "            ],\n",
    "            columns=self.log.columns,\n",
    "        )\n",
    "\n",
    "        # 使用concat()函数添加新行\n",
    "        self.log = pd.concat([self.log, new_row], ignore_index=True)\n",
    "\n",
    "        # print(\n",
    "        #     f\"{time},{self.open_at},{row['Close']},{self.profit},{self.capital},{row['Buy_Signal']},{row['Sell_Signal']},{self.operate},{symbol}\"\n",
    "        # )\n",
    "        pass\n",
    "\n",
    "    def run(self):\n",
    "        for index, row in self.df.iterrows():\n",
    "            currClose = row[\"Close\"]\n",
    "            # 时间范围判断 有仓就撤退\n",
    "            # 提取小时\n",
    "            henale = False\n",
    "            hour = index.hour\n",
    "            accept = [0, 1, 2, 20, 21, 22, 23]\n",
    "            if henale and hour not in accept and (row[\"Sell_Signal\"]):\n",
    "                if self.position != 0:\n",
    "                    self.profit = (\n",
    "                                          short_profit(self.open_at, currClose) - self.fee_profit\n",
    "                                  ) * self.leverage + 1\n",
    "                    if (\n",
    "                            self.profit >= self.take * self.leverage / 1e2 + 1\n",
    "                            or self.profit <= self.stop * self.leverage / 1e2 + 1\n",
    "                    ):\n",
    "                        # self.capital = self.capital * self.profit\n",
    "                        # self.close = row[\"Close\"]\n",
    "                        self.position = 0\n",
    "                        # self.operate += 1\n",
    "                        self.close_cage(index, row, \"Not\")\n",
    "\n",
    "                continue\n",
    "\n",
    "            # 仓位风险\n",
    "            if self.position == -1:\n",
    "                # 涨幅幅\n",
    "                khigh = row[\"High\"] / self.open_at - 1\n",
    "                if khigh >= self.overp:\n",
    "                    self.capital = 0\n",
    "                    print(\"over\")\n",
    "                    break\n",
    "            if self.position == 1:\n",
    "                # 涨幅幅\n",
    "                if row[\"Low\"] / self.open_at >= self.overp:\n",
    "                    self.capital = 0\n",
    "                    break\n",
    "            if self.capital <= 0:\n",
    "                break\n",
    "\n",
    "            # 交易执行\n",
    "            if row[\"Buy_Signal\"] | row[\"Sell_Signal\"]:\n",
    "                if self.position == 0:\n",
    "                    # 趋势检查\n",
    "                    if row[\"ChangeOfChange\"] < self.strong_will:\n",
    "                        continue\n",
    "                    # 初始入场\n",
    "                    if row[\"Sell_Signal\"]:\n",
    "                        self.profit = 1\n",
    "                        self.open_at = row[\"Close\"]\n",
    "                        self.position = -1\n",
    "                        # self.operate += 1\n",
    "                        self.close_cage(index, row, \"Open\")\n",
    "                    continue\n",
    "                # if row[\"Sell_Signal\"]:\n",
    "                # profit = (row[\"Close\"] / close - 1) * leverage + 1\n",
    "                # # 做空\n",
    "                # # 方向改变则结算收益\n",
    "                # if position == 1:\n",
    "                #     capital = capital * profit\n",
    "                # close = row[\"Close\"]\n",
    "                # position = -1\n",
    "                # operate += 1\n",
    "                if row[\"Buy_Signal\"]:\n",
    "                    self.profit = (\n",
    "                                          short_profit(self.open_at, currClose) - self.fee_profit\n",
    "                                  ) * self.leverage + 1\n",
    "                    # 做多\n",
    "                    # 方向改变则结算收益\n",
    "                    # # if position == -1:\n",
    "                    # self. capital = self.capital * self.profit\n",
    "                    # self.close = row[\"Close\"]\n",
    "                    self.position = 0\n",
    "                    # self.operate += 1\n",
    "                    # print(\n",
    "                    #     f\"{index},{close},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Signal\"\n",
    "                    # )\n",
    "                    self.close_cage(index, row, \"Signal\")\n",
    "                    continue\n",
    "\n",
    "            # 单向做空 1.1 * leverage 止盈\n",
    "            # stop&loss\n",
    "            if self.position == -1:\n",
    "                self.profit = (\n",
    "                        short_profit(self.open_at, currClose) * self.leverage\n",
    "                        + 1\n",
    "                        - self.fee_profit\n",
    "                )\n",
    "                want = self.take * self.leverage / 1e2 + 1\n",
    "                if self.profit >= want:\n",
    "                    self.profit = want - self.fee_profit\n",
    "                    # self.capital = self.capital * (want-self.fee_profit)\n",
    "                    # close = row[\"Close\"]\n",
    "                    self.position = 0\n",
    "                    # self.operate += 1\n",
    "                    # print(\n",
    "                    #     f\"{index},{close},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Take\"\n",
    "                    # )\n",
    "                    self.close_cage(index, row, \"Take\")\n",
    "                    continue\n",
    "\n",
    "                if self.profit <= self.loss:\n",
    "                    self.profit = self.loss\n",
    "                    self.position = 0\n",
    "                    self.close_cage(index, row, \"Loss\")\n",
    "                    continue\n",
    "\n",
    "                if (self.auto_stop) & (self.profit <= 1 + self.stop / 1e2):\n",
    "                    # capital = capital * profit\n",
    "                    # close = row[\"Close\"]\n",
    "                    self.position = 0\n",
    "                    # operate += 1\n",
    "                    # print(\n",
    "                    #     f\"{index},{close},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Stop\"\n",
    "                    # )\n",
    "                    self.close_cage(index, row, \"Stop\")\n",
    "                    continue\n",
    "                # else:\n",
    "                #   print(operate,profit)\n",
    "\n",
    "                # df[index][\"Icr\"] = icr\n",
    "\n",
    "\n",
    "backtest = BackTester(df=df)\n",
    "backtest.run()\n",
    "backtest.log.head(1000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 单向做空 buy_signal\n",
    "def strong_will_check():\n",
    "    # pre_close_change = close / prev(close, 1) - 1\n",
    "    # curr_close_change = close / prev(close, 1) - 1\n",
    "    #\n",
    "    # change_of_change = close_change / prev(close_change, 1) - 1\n",
    "    # change_of_change = close_change / prev(close_change, 1) - 1\n",
    "    # change_of_change = close_change / prev(close_change, 1) - 1\n",
    "\n",
    "    in_macd = 1  # optional\n",
    "    next_macd = 1\n",
    "    # 入场bar涨跌幅\n",
    "    in_percentage = -27\n",
    "    # 下一个bar涨跌幅\n",
    "    next_percentage = 24\n",
    "\n",
    "    # in_open =\n",
    "    # in_close =\n",
    "    # 买入一个周期Close不足0.35%幅度撤退\n",
    "    strong_will = 1.5\n",
    "\n",
    "    # B\n",
    "    b_mrate = long_profit(in_macd, next_macd)\n",
    "    b_pct = long_profit(in_percentage, next_percentage)\n",
    "\n",
    "    # S\n",
    "    s_mrate = short_profit(in_macd, next_macd)\n",
    "    s_pct = short_profit(in_percentage, next_percentage)\n",
    "\n",
    "    print(b_pct, s_pct)\n",
    "\n",
    "    data = {\"b\": [b_mrate, b_pct, b_pct >= strong_will], \"s\": [s_mrate, s_pct, s_pct >= strong_will]}\n",
    "    mdf = pd.DataFrame(data)\n",
    "    print(mdf)\n",
    "\n",
    "\n",
    "strong_will_check()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 单向做多 buy_signal 周期达到1.1%幅 时离场\n",
    "# 日K线趋势上升\n",
    "# run on 20-02\n",
    "# backtest\n",
    "\n",
    "capital = 1000\n",
    "open_at = 0\n",
    "position = 0  # -1空 1多\n",
    "leverage = 20\n",
    "overp = 100 / leverage  # 爆仓涨跌幅\n",
    "df = dd.df\n",
    "profit = 0\n",
    "take = 2.5\n",
    "stop = 0.35  # 势力不足撤退 周期达到该幅度\n",
    "operate = 0\n",
    "\n",
    "for index, row in df.iterrows():\n",
    "    currClose = row[\"Close\"]\n",
    "    # 时间范围判断 有仓就撤退\n",
    "    # 提取小时\n",
    "    henale = False\n",
    "    hour = index.hour\n",
    "    accept = [0, 1, 2, 20, 21, 22, 23]\n",
    "    if henale and hour not in accept and (row[\"Buy_Signal\"]):\n",
    "        if position != 0:\n",
    "            profit = long_profit(open_at, currClose) * leverage + 1\n",
    "            if (\n",
    "                    profit >= take * leverage / 1e2 + 1\n",
    "                    or profit <= stop * leverage / 1e2 + 1\n",
    "            ):\n",
    "                capital = capital * profit\n",
    "                # close = row[\"Close\"]\n",
    "                position = 0\n",
    "                operate += 1\n",
    "\n",
    "                print(\n",
    "                    f\"{index},{open_at},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Not\"\n",
    "                )\n",
    "        continue\n",
    "\n",
    "    # 仓位风险\n",
    "    if position == -1:\n",
    "        # 涨幅幅\n",
    "        if row[\"High\"] / open_at >= overp:\n",
    "            capital = 0\n",
    "            break\n",
    "    if position == 1:\n",
    "        # 涨幅幅\n",
    "        if row[\"Low\"] / open_at >= overp:\n",
    "            capital = 0\n",
    "            break\n",
    "\n",
    "    # 交易执行\n",
    "    if row[\"Buy_Signal\"] | row[\"Sell_Signal\"]:\n",
    "        preClose = open_at\n",
    "        if position == 0:\n",
    "            # 初始入场\n",
    "            if row[\"Buy_Signal\"]:\n",
    "                open_at = row[\"Close\"]\n",
    "                position = 1\n",
    "                operate += 1\n",
    "                print(\n",
    "                    f\"{index},{preClose},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},In\"\n",
    "                )\n",
    "            continue\n",
    "        if row[\"Sell_Signal\"]:\n",
    "            profit = long_profit(open_at, currClose) * leverage + 1\n",
    "            # 方向改变则结算收益\n",
    "            if position == 1:\n",
    "                capital = capital * profit\n",
    "            # close = row[\"Close\"]\n",
    "            position = 0\n",
    "            operate += 1\n",
    "            # if row[\"Buy_Signal\"]:\n",
    "            #     profit = (close / row[\"Close\"] - 1) * leverage + 1\n",
    "            #     # 做多\n",
    "            #     # 方向改变则结算收益\n",
    "            #     # if position == -1:\n",
    "            #     capital = capital * profit\n",
    "            #     # close = row[\"Close\"]\n",
    "            #     position = 0\n",
    "            #     operate += 1\n",
    "            print(\n",
    "                f\"{index},{preClose},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Signal\"\n",
    "            )\n",
    "            continue\n",
    "\n",
    "    # 单向做空 1.1 * leverage 止盈\n",
    "    # stop&loss\n",
    "    # if position == 1:\n",
    "    # profit = (1 - currClose / close ) * leverage + 1\n",
    "    #     # if profit >= take * leverage / 1e2 + 1 :#or\n",
    "    #     if profit <= stop * leverage / 1e2 + 1:\n",
    "    #         capital = capital * profit\n",
    "    #         # close = row[\"Close\"]\n",
    "    #         position = 0\n",
    "    #         operate += 1\n",
    "\n",
    "    #         print(\n",
    "    #             f\"{index},{preClose},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Stop\"\n",
    "    #         )\n",
    "\n",
    "    # df[index][\"Icr\"] = icr\n",
    "print(capital)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "open_at = 90769.51\n",
    "now = 88720.03\n",
    "x = now / open_at\n",
    "print(x)\n",
    "print(1 - x)\n",
    "print(open_at * (x - 1) + open_at)  #=now\n",
    "# now/close-1=x\n",
    "\n",
    "l = 1\n",
    "aa = (1 - now / open_at) * l + 1\n",
    "bb = (open_at / now - 1) * l + 1\n",
    "print(aa, bb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# backtest\n",
    "\n",
    "capital = 1000\n",
    "open_at = 0\n",
    "position = 0  # -1空 1多\n",
    "leverage = 20\n",
    "overp = 100 / leverage  # 爆仓涨跌幅\n",
    "df = dd.df\n",
    "profit = 0\n",
    "take = 2.5\n",
    "stop = 0.35  # 势力不足撤退 周期达到该幅度\n",
    "operate = 0\n",
    "\n",
    "# 中性双向交易\n",
    "for index, row in df.iterrows():\n",
    "    # 时间范围判断 有仓就撤退\n",
    "    # 提取小时\n",
    "    henale = False\n",
    "    hour = index.hour\n",
    "    accept = [0, 1, 2, 20, 21, 22, 23]\n",
    "    if henale and hour not in accept and (row[\"Sell_Signal\"]):\n",
    "        if position != 0:\n",
    "            profit = (open_at / row[\"Close\"] - 1) * leverage + 1\n",
    "            if (\n",
    "                    profit >= take * leverage / 1e2 + 1\n",
    "                    or profit <= stop * leverage / 1e2 + 1\n",
    "            ):\n",
    "                capital = capital * profit\n",
    "                # close = row[\"Close\"]\n",
    "                position = 0\n",
    "                operate += 1\n",
    "\n",
    "                print(\n",
    "                    f\"{index},{open_at},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Not\"\n",
    "                )\n",
    "        continue\n",
    "\n",
    "    # 仓位风险\n",
    "    if position == -1:\n",
    "        # 涨幅幅\n",
    "        if row[\"High\"] / open_at >= overp:\n",
    "            capital = 0\n",
    "            break\n",
    "    if position == 1:\n",
    "        # 涨幅幅\n",
    "        if row[\"Low\"] / open_at >= overp:\n",
    "            capital = 0\n",
    "            break\n",
    "\n",
    "    if row[\"Buy_Signal\"] | row[\"Sell_Signal\"]:\n",
    "        if position == 0:\n",
    "            # 初始入场\n",
    "            open_at = row[\"Close\"]\n",
    "            position = 1\n",
    "            if row[\"Buy_Signal\"]:\n",
    "                position = 1\n",
    "            else:\n",
    "                position = -1\n",
    "            operate += 1\n",
    "            continue\n",
    "        elif row[\"Sell_Signal\"]:\n",
    "            profit = (row[\"Close\"] / open_at - 1) * leverage + 1\n",
    "            # 做空\n",
    "            # 方向改变则结算收益\n",
    "            if position == 1:\n",
    "                capital = capital * profit\n",
    "                open_at = row[\"Close\"]\n",
    "                position = -1\n",
    "                operate += 1\n",
    "            print(\n",
    "                f\"{index},{open_at},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},'sellSig'\"\n",
    "            )\n",
    "            continue\n",
    "        elif row[\"Buy_Signal\"]:\n",
    "            profit = (open_at / row[\"Close\"] - 1) * leverage + 1\n",
    "            # 做多\n",
    "            # 方向改变则结算收益\n",
    "            if position == -1:\n",
    "                capital = capital * profit\n",
    "                open_at = row[\"Close\"]\n",
    "                position = 1\n",
    "                operate += 1\n",
    "            continue\n",
    "\n",
    "            print(\n",
    "                f\"{index},{open_at},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},'buySig'\"\n",
    "            )\n",
    "        # print(\n",
    "        #     f\"{index},{close},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate}\"\n",
    "        # )\n",
    "\n",
    "    # stop&loss\n",
    "    if position == -1:\n",
    "        profit = (open_at / row[\"Close\"] - 1) * leverage + 1\n",
    "    elif position == 1:\n",
    "        profit = (row[\"Close\"] - 1 / open_at) * leverage + 1\n",
    "\n",
    "    if position != 0:\n",
    "        if profit >= take * leverage / 1e2 + 1 or profit <= stop * leverage / 1e2 + 1:\n",
    "            capital = capital * profit\n",
    "            # close = row[\"Close\"]\n",
    "            position = 0\n",
    "            operate += 1\n",
    "\n",
    "            print(\n",
    "                f\"{index},{open_at},{row['Close']},{profit},{capital},{row['Buy_Signal']},{row['Sell_Signal']},{operate},Stop\"\n",
    "            )\n",
    "\n",
    "        # df[index][\"Icr\"] = icr\n",
    "\n",
    "capital"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# 生成示例数据\n",
    "x = np.linspace(0, 10, 100)\n",
    "y1 = np.sin(x)\n",
    "y2 = 100 * np.cos(x)\n",
    "\n",
    "# 创建图形和主坐标轴\n",
    "fig, ax1 = plt.subplots()\n",
    "\n",
    "# 绘制第一个数据序列\n",
    "color = \"tab:red\"\n",
    "ax1.set_xlabel(\"x\")\n",
    "ax1.set_ylabel(\"sin(x)\", color=color)\n",
    "ax1.plot(x, y1, color=color)\n",
    "ax1.tick_params(axis=\"y\", labelcolor=color)\n",
    "\n",
    "# 创建第二个坐标轴\n",
    "ax2 = ax1.twinx()\n",
    "\n",
    "# 绘制第二个数据序列\n",
    "color = \"tab:blue\"\n",
    "ax2.set_ylabel(\"100 * cos(x)\", color=color)\n",
    "ax2.plot(x, y2, color=color)\n",
    "ax2.tick_params(axis=\"y\", labelcolor=color)\n",
    "\n",
    "# 显示图形\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dd = MACDKDJRSI(period=\"2mo\", interval=\"1d\")\n",
    "dd.backtest()\n",
    "dd.marketing_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "hh = MACDKDJRSI(period=\"5d\", interval=\"1h\")\n",
    "hh.backtest()\n",
    "hh.marketing_data()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hf = MACDKDJRSI(interval=\"30m\")\n",
    "hf.backtest()\n",
    "hf.marketing_data(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mm = MACDKDJRSI(interval=\"15m\", limit=500)\n",
    "mm.backtest()\n",
    "mm.marketing_data(50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 交易回测\n",
    "# Buy_Signal \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = mm.df\n",
    "# contition = (df['Buy_Signal'] | df['Sell_Signal'])\n",
    "# df['Last_True_Value'] = df['Close'].where(contition ).ffill()\n",
    "# df['Buy_Close'] = df['Close'].where(df['Buy_Signal'] ).ffill()\n",
    "# df['Sell_CLose'] = df['Close'].where(df['Sell_Signal'] ).ffill()\n",
    "\n",
    "last_true_idx = 0\n",
    "for i in range(len(df)):\n",
    "    related_value = 0\n",
    "    if df[:i]['Buy_Signal'].any():\n",
    "        idx = df.index[df['Buy_Signal']].max()\n",
    "        if idx > last_true_idx:\n",
    "            last_true_idx = idx\n",
    "\n",
    "    if df[:i]['Sell_Signal'].any():\n",
    "        last_true_idx = df.index[df['Sell_Signal']].max()\n",
    "        if idx > last_true_idx:\n",
    "            last_true_idx = idx\n",
    "\n",
    "    related_value = df.loc[last_true_idx, 'Close']\n",
    "\n",
    "    df.iloc[i]['Last_True_Value'] = related_value\n",
    "    df.iloc[i]['Sell_Percent'] = df['Close'] / df['Last_True_Value']\n",
    "\n",
    "# pd.set_option('display.max_rows', 500)\n",
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df['Buy_Percent'] = df['Close'] / df['Last_True_Value']\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TODO 更换cctx ohlc数据源\n",
    "# TODO mjr(30m) 信号B/S交易\n",
    "# 38% 7%\n",
    "# 20倍 涨跌幅2%止盈0.35%止损/新信号则反买\n",
    "import os\n",
    "print(os.getcwd())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "m = {\n",
    "    \"max\": 5e3,\n",
    "    \"day\": 24*60/4,\n",
    "    \"base\":10\n",
    "}\n",
    "\n",
    "\n",
    "print(m)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "24*60/5*3"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
